home *** CD-ROM | disk | FTP | other *** search
/ TPUG - Toronto PET Users Group / TPUG Users Group CD / TPUG Users Group CD.iso / AMIGA / AMICUS / AMICUS01.ADF / C / ham.c < prev    next >
C/C++ Source or Header  |  1985-12-29  |  18KB  |  488 lines

  1.  
  2. /* colorful.c: yet another hold and modify demo */
  3.  
  4. /* warning: this extra-half-bright mode works only on revision 6 of the 
  5.     Daphne chip, in Amigas made after first quarter '86 
  6. */
  7.  
  8. #ifdef FOOIE
  9.  
  10. From: bobp@amiga.UUCP (Robert S. Pariseau)
  11. Subject: More Fun with 6 Planes (LONG SOURCE)
  12. Date: 11 Nov 85 10:39:27 GMT
  13. Reply-To: bobp@snake.UUCP (Robert S. Pariseau)
  14. Organization: Commodore-Amiga Inc., 983 University Ave #D, Los Gatos CA 95030
  15.  
  16. TITLE:  More Fun with 6 Planes (LONG SOURCE)
  17.  
  18. The source below is a bit of eye-candy that shows off the use of Hold
  19. and Modify graphics display mode on the Amiga.  Hold and Modify (or HAM
  20. for short) is a compromise between the limited direct color access of
  21. an inexpensive color-palette, frame buffer graphics engine like the
  22. Amiga, and the high cost of a direct reading frame buffer graphic engine
  23. like some of the more expensive CAD systems.  On the Amiga, the bits
  24. associated with a given pixel select one of the 32 color registers.  Each
  25. color register contains a color value consisting of 4 bits of Red
  26. component, 4 bits of Green, and 4 bits of Blue -- yielding 4096 different
  27. colors from black to white.  The Amiga hardware has sufficient bandwidth
  28. to retrieve 6 bit-planes worth of data for a given pixel (4 in high
  29. resolution display).  The combination of these two constraints says that
  30. in a static display (no dynamic color changing going on in the 
  31. background), you can display up to 32 colors simultaneously in low
  32. res and up to 16 colors simultaneously in highs res choosen out of
  33. the palette of 4096 possible colors.
  34.  
  35. [Note: as discussed earlier, you can actually get up to 64 distinct
  36. colors in low res using 6 planes and EXTRA_HALFBRITE display mode.
  37. Further, note that dynamic color changing goes on all the time in
  38. normal Amiga displays -- that's how each of the separately slideable
  39. screens gets its own color palette for instance.]
  40.  
  41. If the Amiga were only somehow capable of pulling in 12 planes of data
  42. per pixel, then we could avoid using the color palette altogether.  We
  43. could encode the desired pixel color (4 bits each R, G, and B) directly
  44. into the frame buffer.  This would allow us to independently choose
  45. any of the 4096 colors for each pixel -- with no limit on how many
  46. different colors appeared in a given display.
  47.  
  48. [Note: there's a downside to this as well.  Since the display doesn't
  49. feed through a color palette, there's no easy way of swapping or
  50. changing colors in your picture -- you have to actually go out and
  51. change all those pixels.  With a color palette, you just change the
  52. color values in the registers.  This trick is fundamental to the
  53. technique of "color cycle animation".]
  54.  
  55. HAM is a color modulation technique which approaches the flexibility
  56. of a direct reading frame buffer.  Using HAM, you can specify any
  57. desired color out of the 4096 available within 3 horizontally
  58. adjacent pixels.  Here is how it works.
  59.  
  60. Consider a 4 plane image.  The 4 bits of each pixel select one of the
  61. first 16 color registers.  Now consider the extra 2 bits per pixel
  62. of a 6 plane HAM image.  Those extra 2 bits are used as control bits,
  63. selecting between the following 4 choices:
  64.  
  65. 0) Use the lower 4 bits as a color register selector, just as normal.
  66.  
  67. 1) Use the lower 4 bits as the Blue component of the color for this
  68.    pixel.  Copy the Red and Green components of the color for this
  69.    pixel from the color of the Playfield pixel immediately to the
  70.    left of this one.
  71.  
  72. 2) Use the lower 4 bits as the Red component of the color for this
  73.    pixel.  Copy the Blue and Green components of the color for this
  74.    pixel from the color of the Playfield pixel immediately to the
  75.    left of this one.
  76.  
  77. 3) Use the lower 4 bits as the Green component of the color for this
  78.    pixel.  Copy the Red and Blue components of the color for this
  79.    pixel from the color of the Playfield pixel immediately to the
  80.    left of this one.
  81.  
  82. Note that only the color produced for the pixel is varied.  The contents
  83. of the color registers themselves are NOT changed by HAM.  Also note
  84. that the effects are cumulative.  Thus, in 3 adjacent pixels, you can
  85. Modify-Red, Modify-Green, and Modify-Blue, thereby producing any color
  86. you want.
  87.  
  88. Finally, note that a Modify-x pixel takes its "Hold" colors from the
  89. color that is OR WOULD HAVE BEEN produced for the PLAYFIELD (i.e.,
  90. frame buffer) pixel immediately to its left.  This means that sprite
  91. images moving over the display do NOT mess up your carefully choosen
  92. HAM colors.
  93.  
  94. There is a hardware mode bit that controls HAM.  A HAM display requires
  95. 5 or 6 bit planes.  If you provide a 5 plane image, the hardware assumes
  96. a 6th bit value of 0 for each pixel -- this means you can only choose
  97. normal and Modify-Blue out of the choices above.
  98.  
  99. The graphics kernel software automatically supports HAM as a ViewPort
  100. attribute.  That means that each of your separately slideable ViewPorts
  101. (Screens in Intuition lingo) can have, or not have, HAM turned on without
  102. affecting the others.
  103.  
  104. BEWARE!  Some of the older developer machines and store demo machines
  105. do not produce reliable HAM images.  ALL of the consumer machines do
  106. HAM just fine.
  107.  
  108. ----------------------------Program Notes:
  109.  
  110. The Colorful program will compile and link cleanly using the native
  111. Amiga Lattice C tools on the standard V1.0 C disk.  The Make script
  112. in the examples directory will do all the work for you.  As usual,
  113. I recommend that you copy the source into ram: disk and then direct
  114. Make at it by typing:
  115.  
  116.   1> execute Make ram:Colorful
  117.  
  118. The program displays 256 boxes each having a different color out of
  119. the possible 4096.  Colorful listens for left mouse button events
  120. and switches between two display modes.  The first is an ordered
  121. display with labelled color components.  The second is a random
  122. display where boxes randomly selected have their color randomly
  123. changed.  Note that at no time do any 2 boxes share the same color.
  124.  
  125. If you are sharp-eyed, you will notice a narrow stripe of red and a
  126. narrow stripe of green at the leading (leftmost) edge of each of the
  127. boxes.  These are the color modifiers in action.  Each box consists
  128. of a vertical line of Modify-Red, followed by a vertical line of
  129. Modify-Green, followed by a rectangle of Modify-Blue as follows:
  130.  
  131.          RGBBBBBBBBB
  132.          RGBBBBBBBBB
  133.          RGBBBBBBBBB
  134.          RGBBBBBBBBB
  135.          RGBBBBBBBBB
  136.          RGBBBBBBBBB
  137.  
  138. The routine hamBox() produces such a box.
  139.  
  140. For further information, see the Amiga Hardware Manual, the Amiga
  141. ROM Kernel Manual, and the manual Intuition:  The Amiga User Interface.
  142.  
  143. ----------------------------Program Source Follows:
  144.  
  145. #endif
  146.  
  147. /***********************************************************************
  148.  *  Colorful -- A demo of the Amiga's Hold and Modify mode, showing, at
  149.  *              all times,  a different subset of 256 of the 4096
  150.  *              colors available on the Amiga.  At any moment, no two
  151.  *              squares have the same exact color in them.
  152.  *
  153.  *  Rob Peck     -- November  5, 1985
  154.  *  Bob Pariseau -- November 10, 1985   (Rework for tutorial)
  155.  *
  156.  **********************************************************************/
  157.  
  158. #include <exec/types.h>
  159. #include <exec/tasks.h>
  160. #include <exec/libraries.h>
  161. #include <exec/devices.h>
  162. #include <devices/keymap.h>
  163. #include <graphics/copper.h>
  164. #include <graphics/display.h>
  165. #include <graphics/gfxbase.h>
  166. #include <graphics/text.h>
  167. #include <graphics/view.h>
  168. #include <graphics/gels.h>
  169. #include <graphics/regions.h>
  170. #include <hardware/blit.h>
  171. #include <intuition/intuition.h>
  172. #include <intuition/intuitionbase.h>
  173.  
  174. #define  XSIZE 11                      /* Color box sizes             */
  175. #define  YSIZE 6
  176.  
  177. struct   GfxBase       *GfxBase;       /* Export the library pointers */
  178. struct   IntuitionBase *IntuitionBase;
  179.  
  180.  
  181. struct   RastPort      *rp;            /* Graphics structures           */
  182. struct   ViewPort      *vp;
  183.  
  184. struct TextAttr TestFont =
  185.     {
  186.        "topaz.font", /* Standard system font */
  187.        8,    0,    0
  188.     };
  189.  
  190. struct   Window        *w;             /* Intuition structures        */ 
  191. struct   Screen        *screen;
  192. struct   IntuiMessage  *message;
  193.  
  194.  
  195. struct NewScreen ns = {
  196.    0, 0,                               /* start position                */
  197.    320, 200, 6,                        /* width, height, depth          */
  198.    0, 1,                               /* detail pen, block pen         */
  199.    HAM,                                /* Hold and Modify ViewMode      */
  200.    CUSTOMSCREEN,                       /* screen type                   */
  201.    &TestFont,                          /* font to use                   */
  202.    " 256 different out of 4096",       /* default title for screen      */
  203.    NULL                                /* pointer to additional gadgets */
  204.    };
  205.  
  206.  
  207. struct NewWindow nw = {
  208.         0, 11,                         /* start position                */
  209.         320, 186,                      /* width, height                 */
  210.         -1, -1,                        /* detail pen, block pen         */
  211.         MOUSEBUTTONS|CLOSEWINDOW,      /* IDCMP flags                   */
  212.         ACTIVATE|WINDOWCLOSE,          /* window flags                  */
  213.         NULL,                          /* pointer to first user gadget  */
  214.         NULL,                          /* pointer to user checkmark     */
  215.         "colors at any given moment",  /*  window title                 */
  216.         NULL,                          /* pointer to screen (set below) */
  217.         NULL,                          /* pointer to superbitmap        */
  218.         0, 0, 320, 186,                /* ignored since not sizeable    */
  219.         CUSTOMSCREEN                   /* type of screen desired        */
  220.         };
  221.  
  222.  
  223.  
  224. LONG  squarecolor[16 * 16], freecolors[4096-(16*16)];
  225. SHORT squares[16 * 16];
  226. SHORT xpos[16], ypos[16];
  227.  
  228. char  *number[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
  229.                     "A", "B", "C", "D", "E", "F" };
  230.  
  231. SHORT sStop, cStop, sequence;
  232. BOOL  textneeded;
  233.  
  234.  
  235.  
  236. main()
  237. {
  238.    ULONG  class;
  239.    USHORT code, i;
  240.    BOOL   wheelmode;
  241.  
  242.    for(i=0; i<16; i++)               /* Establish color square positions */
  243.       {
  244.       xpos[i] = (XSIZE + 4) * i + 20;
  245.       ypos[i] = (YSIZE + 3) * i + 21;
  246.       }
  247.  
  248.    GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0);
  249.    if (GfxBase == NULL) exit();
  250.  
  251.    IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library", 0);
  252.    if (IntuitionBase == NULL)
  253.    {
  254.       CloseLibrary(GfxBase);
  255.       exit();
  256.    }
  257.  
  258.    screen = (struct Screen *)OpenScreen(&ns); 
  259.    if (screen == NULL)
  260.    {
  261.       CloseLibrary(IntuitionBase);
  262.       CloseLibrary(GfxBase);
  263.       exit();
  264.    }
  265.  
  266.    nw.Screen = screen;                /* Open window in our new screen */
  267.    w = (struct Window *)OpenWindow(&nw);
  268.    if (w == NULL)
  269.    {
  270.       CloseScreen(screen);
  271.       CloseLibrary(IntuitionBase);
  272.       CloseLibrary(GfxBase);
  273.       exit();
  274.    }
  275.  
  276.    vp = &screen->ViewPort;             /* Set colors in screen's VP    */
  277.    rp = w->RPort;                      /* Render into the window's RP  */
  278.  
  279.    /*  Set the color registers:  Black, Red, Green, Blue, White */
  280.  
  281.    SetRGB4(vp, 0, 00, 00, 00);   
  282.    SetRGB4(vp, 1, 15, 00, 00);    
  283.    SetRGB4(vp, 2, 00, 15, 00);   
  284.    SetRGB4(vp, 3, 00, 00, 15);
  285.    SetRGB4(vp, 4, 15, 15, 15);
  286.  
  287.    SetBPen(rp, 0);                    /* Insure clean text              */
  288.    textneeded = TRUE;
  289.    wheelmode  = TRUE;                 /* Start with Color Wheel display */
  290.  
  291.    FOREVER
  292.    {  /* Process any and all messages in the queue, then update the     */
  293.       /* display colors once, then come back here to look at the queue  */
  294.       /* again.  If you see a left-mouse-button-down event, then switch */
  295.       /* display modes.  If you see a Close-Window-gadget event, then   */
  296.       /* clean up and exit the program.  NOTE:  This is a BUSY LOOP so  */
  297.       /* that the colors will cycle as quickly as possible.             */
  298.  
  299.       while((message = (struct IntuiMessage *)GetMsg(w->UserPort)) != NULL)
  300.       {
  301.          class = message->Class;
  302.          code  = message->Code;
  303.          ReplyMsg(message);       /* Can't reply until done using it!   */
  304.  
  305.          if(class == CLOSEWINDOW)                   /* Exit the program */
  306.          {
  307.             CloseWindow(w);
  308.             CloseScreen(screen);
  309.             CloseLibrary(IntuitionBase);
  310.             CloseLibrary(GfxBase);
  311.             exit();
  312.          };
  313.  
  314.          if(class == MOUSEBUTTONS && code == SELECTDOWN)  /* swap modes */
  315.          {
  316.             wheelmode = NOT wheelmode;
  317.  
  318.             SetAPen(rp, 0);                   /* Clear the drawing area */
  319.             SetDrMd(rp, JAM1);
  320.             RectFill(rp, 3, 12, 318, 183);
  321.             textneeded = TRUE; 
  322.          }
  323.       }
  324.       if(wheelmode) colorWheel();  else colorFull();
  325.    }
  326. }
  327.  
  328.  
  329. colorFull()              /* Display a ramdomized set of colors          */
  330. {
  331.    SHORT sChoice, cChoice, usesquare;
  332.    LONG  usecolor;
  333.  
  334.    if(textneeded)        /* First call since mode change?               */
  335.    {
  336.        prompt();
  337.        sStop = 255;        /* Top of list of squares yet to change      */
  338.        cStop = 4095 - 256; /* Top of list of colors still needing use   */
  339.  
  340.        for(usecolor=0; usecolor<256; usecolor++)   /* Initialize colors */
  341.        {
  342.           usesquare = usecolor;
  343.           squares[usesquare] = usesquare;
  344.           squarecolor[usesquare] = usecolor;
  345.           hamBox(usecolor, xpos[usesquare % 16], ypos[usesquare / 16]);
  346.        }
  347.  
  348.        for(usecolor=256; usecolor<4095; usecolor++) /* Ones not yet used */
  349.           freecolors[usecolor - 256] = usecolor;
  350.    }
  351.  
  352. /*************************************************************************
  353.  * Randomly choose next square to change such that all squares change
  354.  * color at least once before any square changes twice.  squares[0]
  355.  * through squares[sStop] are the square numbers that have not yet
  356.  * changed in this pass.  RangeRand(r) is an integer function provided
  357.  * in "amiga.lib" which produces a random result in the range 0 to
  358.  * (r-1) given an integer r in the range 1 to 65535.
  359.  ************************************************************************/
  360.  
  361.    sChoice = RangeRand(sStop + 1);        /* Pick a remaining square    */
  362.  
  363.    usesquare = squares[sChoice];          /* Extract square number      */
  364.    squares[sChoice] = squares[sStop];     /* Swap it with sStop slot    */
  365.    squares[sStop] = usesquare;
  366.  
  367.    if(NOT sStop--) sStop = 255;           /* Only one change per pass   */
  368.  
  369. /************************************************************************
  370.  * Randomly choose new color for selected square such that all colors
  371.  * are used once before any color is used again, and such that no two
  372.  * squares simultaneously have the same color.  freecolors[0] through
  373.  * freecolors[cStop] are the colors that have not yet been choosen in
  374.  * this pass.  Note that the 256 colors in use at the end of the
  375.  * previous pass are not available for choice in this pass.
  376.  ***********************************************************************/
  377.  
  378.    cChoice = RangeRand(cStop + 1);
  379.  
  380.    usecolor = freecolors[cChoice];
  381.    freecolors[cChoice] = freecolors[cStop];
  382.    freecolors[cStop] = squarecolor[usesquare];
  383.    squarecolor[usesquare] = usecolor;
  384.  
  385.    if(NOT cStop--) cStop = 4095 - 256;
  386.       
  387.  
  388.    hamBox(usecolor, xpos[usesquare % 16], ypos[usesquare / 16]);
  389. }
  390.  
  391.  
  392. colorWheel()                  /* Display an ordered set of colors */
  393. {
  394.    SHORT  i, j;
  395.  
  396.    if(textneeded)
  397.    {
  398.       prompt();
  399.  
  400.       SetAPen(rp, 2);              /* Green pen for green color numbers */
  401.       Move(rp, 260, ypos[15]+17);
  402.       Text(rp, "Green", 5);
  403.       for(i=0; i<16; i++)
  404.       {
  405.          Move(rp, xpos[i]+3, ypos[15]+17);
  406.          Text(rp, number[i], 1);
  407.       }
  408.  
  409.       SetAPen(rp, 3);              /* Blue pen for blue color numbers   */
  410.       Move(rp, 4, 18);
  411.       Text(rp, "Blue", 4);
  412.       for(i=0; i<16; i++)
  413.       {
  414.          Move(rp, 7, ypos[i]+6);
  415.          Text(rp, number[i], 1);
  416.       }
  417.  
  418.       SetAPen(rp, 1);              /* Red pen for red color numbers     */
  419.       Move(rp, 271, 100);
  420.       Text(rp, "Red", 3);
  421.  
  422.       sequence = 0;
  423.    }
  424.  
  425.    SetAPen(rp, 1);                 /* Identify the red color in use     */
  426.    SetDrMd(rp, JAM2);
  427.    Move(rp, 280, 115);
  428.    Text(rp, number[sequence], 1);
  429.  
  430.    for(j=0; j<16; j++)             /* Update all of the squares         */
  431.       for(i=0; i<16; i++)
  432.          hamBox((sequence<<8 | i<<4 | j), xpos[i], ypos[j]);
  433.  
  434.    if(++sequence == 16) sequence=0;
  435. }
  436.  
  437.  
  438. prompt()                           /* Display mode changing prompt */
  439. {
  440.    SetDrMd(rp, JAM2);
  441.    SetAPen(rp, 4);
  442.    Move(rp, 23, 183);
  443.    Text(rp, "[left mouse button = new mode]", 30);
  444.    textneeded = FALSE;
  445. }
  446.  
  447.  
  448. /**********************************************************************
  449.  *  hamBox() -- routine to draw a colored box in Hold and Modify mode.
  450.  *              Draws a box of size XSIZE by YSIZE with an upper left
  451.  *              corner at (x,y).  The desired color is achieved in 3
  452.  *              steps on each horizontal line of the box.  First we
  453.  *              set the red component, then the green, then the blue.
  454.  *              We achieve this by drawing a vertical line of Modify-Red,
  455.  *              followed by a vertical line of Modify-Green, followed by
  456.  *              a rectangle of Modify-Blue.  Note that the resulting
  457.  *              color for the first two vertical lines depends upon the
  458.  *              color(s) of the pixels immediately to the left of that
  459.  *              line.  By the time we reach the rectangle we are assured
  460.  *              of getting (and maintaining) the desired color because
  461.  *              we have set all 3 components (R, G, and B) straight from
  462.  *              the bit map.
  463.  ***********************************************************************/
  464. hamBox(color, x, y)
  465. LONG   color, x, y;
  466. {
  467.    SHORT  c;
  468.  
  469.    SetDrMd(rp, JAM1);      /* Establish Drawing Mode in RastPort       */
  470.  
  471.    c=((color & 0xf00)>>8); /* Extract desired Red color component.     */
  472.    SetAPen(rp, c + 0x20);  /* Hold G, B from previous pixel.  Set R=n. */
  473.    Move(rp, x, y);
  474.    Draw(rp, x, y+YSIZE);
  475.  
  476.    x++;
  477.    c=((color & 0xf0)>>4);  /* Extract desired Green color component.   */
  478.    SetAPen(rp, c + 0x30);  /* Hold R, B from previous pixel.  Set G=n. */
  479.    Move(rp, x, y);
  480.    Draw(rp, x, y+YSIZE);
  481.  
  482.    x++;
  483.    c=(color & 0xf);        /* Extract desired Blue color component.    */
  484.    SetAPen(rp, c + 0x10);  /* Hold R, G from previous pixel.  Set B=n. */
  485.    RectFill(rp, x, y, x+XSIZE-2, y+YSIZE);
  486. }
  487.  
  488.